/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.pehulja.mmdo.coursework.math;

import com.pehulja.mmdo.coursework.math.exceptions.EquationsHasToMuchVariablesException;
import java.io.Serializable;

import java.util.Collections;
import java.util.List;

/**
 * This class implements inequality entity with left (with variables) and right (only coefficients) function
 * And Inequality sight
 */
public class Equation implements Serializable, Cloneable{
    public static enum InequalitySight {BIGGER, BIGGERorEQ, EQ, SMALLERorEQ, SMALLER}

    private IFunction Left, Right;
    private InequalitySight inequalitySight;

    public Equation() {
        super();
        Left = new PolinomialFunc();
        Right = new PolinomialFunc();
    }

    public Equation(int variablesNumber) {
        super();
        Left = new PolinomialFunc(variablesNumber);
        Right = new PolinomialFunc();
    }

    public Equation(IFunction left, IFunction right, InequalitySight inequalitySight) {
        Left = left;
        Right = right;
        this.inequalitySight = inequalitySight;
    }

    public IFunction getLeft() {
        return Left;
    }

    public void setLeft(IFunction Left) {
        this.Left = Left;
    }

    public IFunction getRight() {
        return Right;
    }

    public void setRight(IFunction Right) {
        this.Right = Right;
    }

    public InequalitySight getInequalitySight() {
        return inequalitySight;
    }

    public void setInequalitySight(InequalitySight inequalitySight) {
        this.inequalitySight = inequalitySight;
    }

    public Double solve() throws EquationsHasToMuchVariablesException {
        if (Left.isMonoVariable() == false)
            throw new EquationsHasToMuchVariablesException();
        return null;
    }

    /**
     * Method, that checks if some roots suits to this inequality
     * @param roots param that must be checked if it suits the inequality
     * @return  true - if suits and false - otherwise
     */
    public boolean checkIfItSuites(double[] roots) {
        double leftPartValue, rightPartValue;

        //Counting value of left and right part of inequality
        leftPartValue = Left.countValue(roots);
        rightPartValue = Right.countValue(roots);

        //Сomparison of this values accorsing to the inequality sight
        if (inequalitySight == InequalitySight.BIGGERorEQ)
            return leftPartValue >= rightPartValue;
        else if (inequalitySight == InequalitySight.BIGGER)
            return leftPartValue > rightPartValue;
        else if (inequalitySight == InequalitySight.SMALLERorEQ)
            return leftPartValue <= rightPartValue;
        else if (inequalitySight == InequalitySight.SMALLER)
            return leftPartValue < rightPartValue;
        else
            return leftPartValue == rightPartValue;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(Left == null ? "0" : Left.toString());
        switch (inequalitySight) {
            case BIGGER:
                builder.append(" > ");
                break;
            case BIGGERorEQ:
                builder.append(" >= ");
                break;
            case EQ:
                builder.append(" = ");
                break;
            case SMALLERorEQ:
                builder.append(" <= ");
                break;
            case SMALLER:
                builder.append(" < ");
                break;
            default:
                return null;
        }
        builder.append(Right == null ? "0" : Right.toString());
        return builder.toString();
    }

    /**
     * Converting inequality to "standard" form and completing it`s left part to all variables (0.0x(n)^n have to exists)
     * "Standard" - form when variables are to the left side of sight - and free coefficients - to the right one
     * After manipulations both part are simplifying
     */

    public void toStandardForm() {
        List<Term> leftFuncComp = getLeft().getComponents();
        List<Term> rightFuncComp = getRight().getComponents();
        for (int i = 0; i < leftFuncComp.size(); i++)
            if (leftFuncComp.get(i).getDegree() <= 0) {
                leftFuncComp.get(i).setFactor(leftFuncComp.get(i).getFactor() * -1);
                rightFuncComp.add(leftFuncComp.get(i));
                leftFuncComp.remove(i);
            }
        for (int i = 0; i < rightFuncComp.size(); i++)
            if (rightFuncComp.get(i).getDegree() > 0) {
                rightFuncComp.get(i).setFactor(rightFuncComp.get(i).getFactor() * -1);
                leftFuncComp.add(rightFuncComp.get(i));
                rightFuncComp.remove(i);
            }
        getLeft().simplify();
        getRight().simplify();
        getLeft().completeToAllVars(getLeft().getListVarsId());
    }

    /**
     * Method converting source inequality to canonical form
     * This method used only while converting the whole LiniarProgramTask to canonical form
     * @param vars list of variables used in task
     */
    public void toCanonicalForm(List<Byte> vars) {
        toStandardForm();
        Byte lastVarId = Collections.max(vars);
        if (getInequalitySight().equals(InequalitySight.BIGGER) || getInequalitySight().equals(InequalitySight.BIGGERorEQ)) {
            getLeft().getComponents().add(new Term(-1, 1, ++lastVarId));
        } else if (getInequalitySight().equals(InequalitySight.SMALLER) || getInequalitySight().equals(InequalitySight.SMALLERorEQ)) {
            getLeft().getComponents().add(new Term(1, 1, ++lastVarId));
        }
        inequalitySight = InequalitySight.EQ;
        getLeft().completeToAllVars(getLeft().getListVarsId());
    }
    
    public Equation copy() {
        return new Equation(this.Left.copy(), this.Right.copy(), inequalitySight);
    }
    
    

}